namespace Brjnk.GpxExplorer.Computing
{
    using System;
    using Brjnk.GpxExplorer.ViewModel;

    /// <summary>
    /// </summary>
    public class TrackCalculationContext
    {
        private bool newSegment = true;

        private TrackPointVM[] last = new TrackPointVM[4];

        private TrackPointVM firstPoint;

        private bool[] isInCurrentSegment = new bool[4];

        private TrackPointVM firstPointInSegment;

        public TrackCalculationContext()
        {
        }

        public void ProcessPoint(TrackPointVM point)
        {
            if (newSegment) firstPointInSegment = point;
            if (firstPoint == null) firstPoint = point;

            if (point == null) throw new InvalidOperationException();
            last[0] = point;
            isInCurrentSegment[0] = true;
            if (point.Source.Elevation.HasValue)
            {
                last[(int)AttributeBasedOn.Elevation] = point;
                isInCurrentSegment[(int)AttributeBasedOn.Elevation] = true;
            }
            if (point.Source.Time.HasValue)
            {
                last[(int)AttributeBasedOn.Time] = point;
                isInCurrentSegment[(int)AttributeBasedOn.Time] = true;
            }
            if (point.Source.Time.HasValue && point.Source.Elevation.HasValue)
            {
                last[(int)(AttributeBasedOn.Elevation | AttributeBasedOn.Time)] = point;
                isInCurrentSegment[(int)(AttributeBasedOn.Elevation | AttributeBasedOn.Time)] = true;
            }
            newSegment = false;
            point = null;
        }

        public void StartNewSegment()
        {
            for (int i = 0; i < isInCurrentSegment.Length; i++)
                isInCurrentSegment[i] = false;
            firstPointInSegment = null;

            newSegment = true;
        }

        public bool IsNewSegment
        {
            get { return newSegment; }
        }

        public TrackPointVM Last
        {
            get { return last[0]; }
        }

        public TrackPointVM LastWithTime
        {
            get { return last[(int)AttributeBasedOn.Time]; }
        }

        public TrackPointVM LastWithElevation
        {
            get { return last[(int)AttributeBasedOn.Elevation]; }
        }

        public TrackPointVM LastWithTimeElevation
        {
            get { return last[(int)(AttributeBasedOn.Elevation | AttributeBasedOn.Time)]; }
        }

        public bool IsLastInSegment
        {
            get { return isInCurrentSegment[0]; }
        }

        public bool IsLastWithTimeInSegment
        {
            get { return isInCurrentSegment[(int)AttributeBasedOn.Time]; }
        }

        public bool IsLastWithElevationInSegment
        {
            get { return isInCurrentSegment[(int)AttributeBasedOn.Elevation]; }
        }

        public bool IsLastWithTimeElevationInSegment
        {
            get { return isInCurrentSegment[(int)(AttributeBasedOn.Elevation | AttributeBasedOn.Time)]; }
        }

        public TrackPointVM FirstPoint
        {
            get { return firstPoint; }
        }

        public TrackPointVM FirstPointInSegment
        {
            get { return firstPointInSegment; }
        }

        [Flags()]
        private enum AttributeBasedOn
        {
            Elevation = 1,
            Time = 2
        }
    }
}